package middleware

import (
	"fmt"
	"strings"
	"time"

	"github.com/gin-gonic/gin"
	"github.com/golang-jwt/jwt/v5"

	"hrms-api/config"
	"hrms-api/handler"
	"hrms-api/model"
	"hrms-api/utils"
)

// Claims JWT claims结构
type Claims struct {
	UserID   uint   `json:"user_id"`
	Username string `json:"username"`
	RoleIDs  []uint `json:"role_ids"`
	jwt.RegisteredClaims
}

// Auth JWT认证中间件
func Auth() gin.HandlerFunc {
	return func(c *gin.Context) {
		// 获取Authorization header
		authorization := c.GetHeader("Authorization")
		if authorization == "" {
			handler.Unauthorized(c, "请先登录")
			c.Abort()
			return
		}

		// 检查Token格式
		parts := strings.SplitN(authorization, " ", 2)
		if !(len(parts) == 2 && parts[0] == "Bearer") {
			handler.Unauthorized(c, "无效的Token格式")
			c.Abort()
			return
		}

		// 解析Token
		claims, err := utils.ParseToken(parts[1])
		if err != nil {
			handler.Unauthorized(c, err.Error())
			c.Abort()
			return
		}

		// 验证用户角色
		var roles []model.Role
		model.DB.Model(&model.UserRole{}).
			Joins("JOIN roles ON user_roles.role_id = roles.id").
			Where("user_roles.user_id = ?", claims.UserID).
			Find(&roles)

		if len(roles) == 0 {
			handler.Unauthorized(c, "用户无有效角色")
			c.Abort()
			return
		}

		// 将用户信息存入上下文
		c.Set("user_id", claims.UserID)
		c.Set("username", claims.Username)
		c.Set("roles", roles)

		c.Next()
	}
}

// GenerateToken 生成JWT Token
func GenerateToken(userID uint, username string, roles []model.Role) (string, error) {
	cfg := config.GetConfig()

	// 解析过期时间
	expireDuration, err := time.ParseDuration(cfg.JWT.Expire)
	if err != nil {
		return "", fmt.Errorf("无效的过期时间格式: %v", err)
	}

	// 获取角色ID列表
	var roleIDs []uint
	for _, role := range roles {
		roleIDs = append(roleIDs, role.ID)
	}

	// 创建Claims
	claims := Claims{
		UserID:   userID,
		Username: username,
		RoleIDs:  roleIDs,
		RegisteredClaims: jwt.RegisteredClaims{
			ExpiresAt: jwt.NewNumericDate(time.Now().Add(expireDuration)),
			IssuedAt:  jwt.NewNumericDate(time.Now()),
			Issuer:    cfg.JWT.Issuer,
		},
	}

	// 生成Token
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	return token.SignedString([]byte(cfg.JWT.Secret))
}
